package com.gcloud.mesh.dcs.strategy;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

import org.jeecg.common.exception.MyBusinessException;
import org.jeecg.common.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.ecs20140526.models.DescribeInstancesRequest;
import com.aliyun.ecs20140526.models.DescribeInstancesResponse;
import com.aliyun.ecs20140526.models.DescribeInstancesResponseBody;
import com.aliyun.smc20190601.Client;
import com.aliyun.smc20190601.models.DescribeReplicationJobsResponseBody;
import com.aliyun.teaopenapi.models.Config;
import com.gcloud.mesh.asset.dao.CloudResourceConfigDao;
import com.gcloud.mesh.asset.dao.CloudResourceDao;
import com.gcloud.mesh.asset.entity.CloudResourceConfigEntity;
import com.gcloud.mesh.dcs.dao.AppDao;
import com.gcloud.mesh.dcs.dao.SchedulerStepDao;
import com.gcloud.mesh.dcs.entity.AppEntity;
import com.gcloud.mesh.dcs.entity.SchedulerStepEntity;
import com.gcloud.mesh.dcs.enums.SchedulerStepStatus;
import com.gcloud.mesh.dcs.strategy.process.AliMigrationProcess;
import com.gcloud.mesh.header.param.AliMigrationParam;
import com.gcloud.mesh.header.vo.dcs.ALiVMInstantInfoVO;
import com.gcloud.mesh.header.vo.dcs.AppVo;
import com.gcloud.mesh.header.vo.dcs.DescribeMetricVO;
import com.gcloud.mesh.supplier.dao.SupplierDao;
import com.gcloud.mesh.supplier.entity.SupplierEntity;
import com.gcloud.mesh.supplier.enums.SystemType;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import lombok.extern.slf4j.Slf4j;

//@Component
@Slf4j
public class AliMigrationStrategy implements ServerMigrationStrategy {

    @Autowired
    private SchedulerStepDao schedulerStepDao;

    @Autowired
    private SupplierDao supplierDao;

    @Autowired
    private CloudResourceDao cloudResourceDao;

    @Autowired
    private AliMigrationProcess aliMigrationProcess;

    @Autowired
    private AppDao appDao;

    @Autowired
    private RedisUtil redisUtil;
    
    @Autowired
    private CloudResourceConfigDao cloudResourceConfigDao;



    @Override
    public Object doMigration(Serializable p) {
        AliMigrationParam aliMigrationParam = JSONObject.toJavaObject((JSONObject)p,AliMigrationParam.class);

        log.info("====>>>>>>>阿里云迁移参数："+JSONObject.toJSONString(aliMigrationParam));

        String myJobId = aliMigrationParam.getMyJobId();

        String accessKeyId = aliMigrationParam.getAccessKeyId();
        String accessSecret = aliMigrationParam.getAccessSecret();
        String regionId= aliMigrationParam.getRegionId();

        //目标阿里云服务器ECS的系统盘大小
        Integer systemDiskSize = aliMigrationParam.getSystemDiskSize();

        Client client = aliMigrationProcess.createSMCClient(accessKeyId,accessSecret);

        //获取源实例信息
        ALiVMInstantInfoVO vo = aliMigrationProcess.getSrcInstanceInfo(myJobId, accessKeyId, accessSecret, aliMigrationParam.getSrcRegionId(), aliMigrationParam.getSrcInstanceId(),10);
        redisUtil.set("migration:ali:srcInstance:"+myJobId,JSONObject.toJSONString(vo),24*60*60);

        Object imageId = redisUtil.get("migration:ali:image:" + vo.getInstanceId());
        if(imageId!=null && aliMigrationProcess.findAndCheckImage(myJobId,accessKeyId,accessSecret,regionId,imageId.toString(),10)){
            //跳过创建迁移镜像任务
            SchedulerStepEntity sse = new SchedulerStepEntity();
            sse.setBeginTime(new Date());
            sse.setId(UUID.randomUUID().toString());
            sse.setName("跳过创建迁移镜像任务");
            sse.setSchedulerJobId(myJobId);
            sse.setStatus(SchedulerStepStatus.PROGRESS.getValue());
            JSONObject attach = new JSONObject();
            attach.put("destRegionId",regionId);
            attach.put("srcRegionId",aliMigrationParam.getSrcRegionId());
            attach.put("srcInstanceId",aliMigrationParam.getSrcInstanceId());
            attach.put("accessKeyId",accessKeyId);
            attach.put("accessSecret",accessSecret);
            attach.put("imageId",imageId);
            attach.put("myJobId",myJobId);
            sse.setAttach(attach.toString());
            sse.setSchedulerType(SystemType.ALI.getName());
            sse.setStepNo(2);
            schedulerStepDao.save(sse);
        }else{
            try {
                //查找迁移任务ID
                String sourceId = aliMigrationProcess.queryJobId(myJobId, client, aliMigrationParam.getSrcAppName());
                //创建迁移任务
                String jobId = aliMigrationProcess.createReplicationJob4Image(myJobId, client, sourceId, systemDiskSize, regionId);
                //启动迁移任务
                aliMigrationProcess.startReplicationJob(myJobId, client, jobId);
                //查询迁移任务状态
                SchedulerStepEntity sse = new SchedulerStepEntity();
                sse.setBeginTime(new Date());
                sse.setId(UUID.randomUUID().toString());
                sse.setName("检查迁移进度");
                sse.setSchedulerJobId(myJobId);
                sse.setStatus(SchedulerStepStatus.PROGRESS.getValue());
                JSONObject attach = new JSONObject();
                attach.put("destRegionId", regionId);
                attach.put("srcRegionId", aliMigrationParam.getSrcRegionId());
                attach.put("srcInstanceId", aliMigrationParam.getSrcInstanceId());
                attach.put("accessKeyId", accessKeyId);
                attach.put("accessSecret", accessSecret);
                attach.put("jobId", jobId);
                attach.put("sourceId", sourceId);
                attach.put("myJobId", myJobId);
                sse.setAttach(attach.toString());
                sse.setSchedulerType(SystemType.ALI.getName());
                sse.setStepNo(1);
                schedulerStepDao.save(sse);
            }catch (Exception e){
                log.error("SMC迁移失败",e);
                throw new MyBusinessException("SMC迁移失败");
            }
        }
        return null;
    }

    @Override
    public List<AppEntity> queryServerList(String cloudResourceId) {

		CloudResourceConfigEntity cloudResource = cloudResourceConfigDao.findOneByProperty("cloud_resource_id", cloudResourceId);
        if(cloudResource==null) return Lists.newArrayList();

        AliMigrationParam aliMigrationParam = JSONObject.toJavaObject(JSONObject.parseObject(cloudResource.getConfig()), AliMigrationParam.class);

        Config config = new Config()
                // 您的AccessKey ID
                .setAccessKeyId(aliMigrationParam.getAccessKeyId())
                // 您的AccessKey Secret
                .setAccessKeySecret(aliMigrationParam.getAccessSecret());
        // 访问的域名
        config.endpoint = "ecs."+aliMigrationParam.getRegionId()+".aliyuncs.com";

        com.aliyun.ecs20140526.Client client = null;
        try {
            client = new  com.aliyun.ecs20140526.Client(config);
            DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest()
                    .setRegionId(aliMigrationParam.getRegionId())
                    .setMaxResults(100);
            DescribeInstancesResponse describeInstancesResponse = client.describeInstances(describeInstancesRequest);
            DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstances instances = describeInstancesResponse.getBody().getInstances();
            List<DescribeInstancesResponseBody.DescribeInstancesResponseBodyInstancesInstance> instance = instances.getInstance();
            return instance.stream().map(i -> {
                AppEntity app = new AppEntity();
                app.setId(i.getInstanceId());
                app.setName(i.getHostName());
                return app;
            }).collect(Collectors.toList());
        } catch (Exception e) {
            log.error("查询阿里云虚拟机列表错误",e);
            throw new MyBusinessException("查询阿里云虚拟机列表错误");
        }
    }

    @Override
    public List<DescribeMetricVO> queryDescribeMetricLastList(String datacenterId) {
        List<AppVo> appList = appDao.getByDatacenterId(datacenterId);
        Map<String,String> appMap = Maps.newHashMap();
        if(appList!=null && !appList.isEmpty()){
            List<JSONObject> dimensions = appList.stream().map(a -> {
                JSONObject json = new JSONObject();
                json.put("instanceId", a.getId());
                appMap.put(a.getId(),a.getName());
                return json;
            }).collect(Collectors.toList());
            SupplierEntity supplierEntity = supplierDao.findOneByProperty("datacenterId", datacenterId);
            if(supplierEntity!=null){
                AliMigrationParam aliMigrationParam = JSONObject.toJavaObject(JSONObject.parseObject(supplierEntity.getConfig()), AliMigrationParam.class);
                String accessKeyId = aliMigrationParam.getAccessKeyId();
                String accessKeySecret = aliMigrationParam.getAccessSecret();
                Config config = new Config()
                        // 您的AccessKey ID
                        .setAccessKeyId(accessKeyId)
                        // 您的AccessKey Secret
                        .setAccessKeySecret(accessKeySecret);
                // 访问的域名
                config.endpoint = "metrics."+aliMigrationParam.getRegionId()+".aliyuncs.com";
                try {
                    com.aliyun.cms20190101.Client client =  new com.aliyun.cms20190101.Client(config);
                    com.aliyun.cms20190101.models.DescribeMetricLastRequest describeMetricLastRequest = new com.aliyun.cms20190101.models.DescribeMetricLastRequest()
                            .setMetricName("cpu_total")
                            .setDimensions(JSONObject.toJSONString(dimensions))
                            .setNamespace("acs_ecs_dashboard");
                    // CPU
                    String datapoints = client.describeMetricLast(describeMetricLastRequest).getBody().getDatapoints();
                    JSONArray jsonArray = JSONArray.parseArray(datapoints);
                    List<DescribeMetricVO> resultList = Lists.newArrayList();
                    for (Object o : jsonArray) {
                        if(o instanceof JSONObject){
                            JSONObject json = (JSONObject)o;
                            String instanceId = json.getString("instanceId");
                            String cpuVal = json.getString("Average");
                            resultList.add(new DescribeMetricVO().setInstanceId(instanceId).setCupVal(cpuVal).setInstanceName(appMap.get(instanceId)));
                        }
                    }

                    //内存
                    describeMetricLastRequest.setMetricName("memory_usedutilization");
                    datapoints = client.describeMetricLast(describeMetricLastRequest).getBody().getDatapoints();
                    jsonArray = JSONArray.parseArray(datapoints);
                    Map<String,String> memMap = Maps.newHashMap();
                    for (Object o : jsonArray) {
                        if(o instanceof JSONObject){
                            JSONObject json = (JSONObject)o;
                            String instanceId = json.getString("instanceId");
                            String memVal = json.getString("Average");
                            memMap.put(instanceId,memVal);
                        }
                    }
                    return resultList.stream().map(d->{
                        return d.setMemVal(memMap.get(d.getInstanceId()));
                    }).collect(Collectors.toList());

                } catch (Exception e) {
                    log.error("查询阿里云虚拟机使用情况错误",e);
                    throw new MyBusinessException("查询阿里云虚拟机使用情况错误");
                }

            }

        }

        return Lists.newArrayList();
    }


    @Override
    public Boolean checkStatus(Integer stepNo, String attach) {
        try {
            if(stepNo==2) return true;
            JSONObject json = JSONObject.parseObject(attach);
            String accessKeyId = json.getString("accessKeyId");
            String accessSecret = json.getString("accessSecret");
            String jobId = json.getString("jobId");
            String sourceId = json.getString("sourceId");
            DescribeReplicationJobsResponseBody.DescribeReplicationJobsResponseBodyReplicationJobsReplicationJob dd = aliMigrationProcess.describeReplicationJobs(accessKeyId, accessSecret, jobId, sourceId);
            return dd == null ? false : ("Finished".equalsIgnoreCase(dd.getStatus()));
        }catch (Exception e){
            log.error("checkStatus",e);
            return false;
        }
    }

    @Override
    public String getStrategyName() {
        return SystemType.ALI.getName();
    }





}
